import psutil
import socket
import tkinter as tk
from tkinter import ttk, font
from tkinter.scrolledtext import ScrolledText

class NetworkMonitorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("网络连接监控工具")
        self.root.geometry("1000x600")
        self.setup_ui()
        
    def setup_ui(self):
        # 设置程序图标和样式
        self.root.configure(bg="#f0f0f0")
        
        # 创建标题
        title_font = font.Font(family="微软雅黑", size=16, weight="bold")
        title_label = tk.Label(self.root, text="系统网络连接监控", font=title_font, bg="#f0f0f0")
        title_label.pack(pady=10)
        
        # 创建主框架
        main_frame = tk.Frame(self.root, bg="#f0f0f0")
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 创建表格
        columns = ("进程名称", "进程ID", "可执行文件路径", "本地地址", "远程地址", "连接状态")
        self.tree = ttk.Treeview(main_frame, columns=columns, show="headings", selectmode="browse")
        
        # 设置列标题和宽度
        for col in columns:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=120, anchor="center")
        
        # 添加滚动条
        scrollbar_y = ttk.Scrollbar(main_frame, orient="vertical", command=self.tree.yview)
        scrollbar_x = ttk.Scrollbar(main_frame, orient="horizontal", command=self.tree.xview)
        self.tree.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
        
        # 放置表格和滚动条
        self.tree.grid(row=0, column=0, sticky='nsew')
        scrollbar_y.grid(row=0, column=1, sticky='ns')
        scrollbar_x.grid(row=1, column=0, sticky='ew')
        
        # 设置行为权重，使表格可以随窗口调整大小
        main_frame.grid_rowconfigure(0, weight=1)
        main_frame.grid_columnconfigure(0, weight=1)
        
        # 底部状态栏
        self.status_bar = tk.Label(self.root, text="就绪", bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 添加刷新按钮
        refresh_button = tk.Button(
            self.root, 
            text="刷新数据", 
            command=self.refresh_data,
            bg="#4CAF50",
            fg="white",
            font=("微软雅黑", 10),
            padx=10,
            pady=5
        )
        refresh_button.pack(pady=10)
        
        # 初始化表格数据
        self.refresh_data()
    
    def refresh_data(self):
        # 清空现有数据
        for item in self.tree.get_children():
            self.tree.delete(item)
            
        # 更新状态栏
        self.status_bar.config(text="正在扫描网络连接...")
        
        try:
            # 获取网络连接信息
            connections = psutil.net_connections(kind='inet')
            
            # 处理并显示数据
            for conn in connections:
                pid = conn.pid
                process_name = "Unknown"
                exe_path = "Unknown"
                local_address = "None"
                remote_address = "None"
                status = "N/A"
                
                try:
                    # 获取进程对象
                    if pid > 0:  # PID为0通常是系统进程，可能无法获取信息
                        process = psutil.Process(pid)
                        # 获取进程名称
                        process_name = process.name() or "Unknown Process"
                        # 获取进程可执行文件路径
                        exe_path = process.exe() or "Unknown Executable"
                except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                    # 处理进程已终止、无权限或僵尸进程的情况
                    process_name = "Access Denied"
                    exe_path = "N/A"
                
                # 解析本地地址和端口
                if conn.laddr:
                    local_address = f"{conn.laddr.ip}:{conn.laddr.port}"
                # 解析远程地址和端口（UDP 可能无远程地址）
                if conn.raddr:
                    remote_address = f"{conn.raddr.ip}:{conn.raddr.port}"
                # 连接状态（仅 TCP 有效）
                if conn.family == socket.AF_INET and conn.type == socket.SOCK_STREAM:
                    status = conn.status
                
                # 插入数据到表格
                self.tree.insert("", "end", values=(
                    process_name,
                    pid,
                    exe_path,
                    local_address,
                    remote_address,
                    status
                ))
            
            # 更新状态栏
            self.status_bar.config(text=f"完成扫描，共发现 {len(connections)} 个网络连接")
            
        except Exception as e:
            # 发生错误时显示错误信息
            self.status_bar.config(text=f"扫描出错: {str(e)}")
            
            # 在表格中显示错误信息
            self.tree.insert("", "end", values=(
                "ERROR",
                "0",
                str(e),
                "N/A",
                "N/A",
                "N/A"
            ))

# 创建应用程序实例
if __name__ == "__main__":
    root = tk.Tk()
    app = NetworkMonitorApp(root)
    root.mainloop()